﻿//
//  Projekt         :   Minesweeper Autosolver
//  Autoren         :   Patrick Brenner, Tobias Rudolph 
//  Institution     :   DHBW Stuttgart
//  Betreuer        :   Martin Kissel    
//  Version         :   1.0.0 
//  Letzte Änderung :   09.06.2013
//  Funktionsinhalte:
//  - Minesweeper Fenster verschieben
//  - Feldgröße auslesen
//  - Bitmap erzeugen 
//  - Felder erkennen 
//  - einfaches Lösen
//  - 1-2-1 Pattern
//  - 1-2-2-1 Pattern
//  - Klick events
//  - GUI
//  - erweitertes Lösen

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Configuration;
using System.IO;
using System.Threading;

namespace Minesweeper_Autosolver
{
    public partial class Hauptfenster : Form
    {
        #region Structures

        // Struktur zum Bearbeiten der Grafik des Minesweeperfeldes
        public struct SquarePos
        {
            public int MiddleX
            {
                get
                {
                    return (Bounds.left + Bounds.right) / 2;
                }
            }
            public int MiddleY
            {
                get
                {
                    return (Bounds.top + Bounds.bottom) / 2;
                }
            }
            public Rect Bounds;
            public Boolean Complete;
        }

        // Struktur zum Bearbeiten der Grafik des Minesweeperfeldes
        public struct Rect
        {
            public int left;
            public int top;
            public int right;
            public int bottom;

            public int Width
            {
                get
                {
                    return right - left;
                }
            }

            public int Height
            {
                get
                {
                    return bottom - top;
                }
            }
        }

        /// <summary>
        /// struct offener Felder für advancedTask
        /// </summary>
        private struct advOffeneFelder
        {
            public int x { get; set; }
            public int y { get; set; }
        }

        /// <summary>
        /// struct verdeckter Felder für advancedTask
        /// </summary>
        private struct advVerdeckteFelder
        {
            public int x { get; set; }
            public int y { get; set; }
            public bool bombe { get; set; }
        }

        #endregion


        #region Import

        // Importiert Methoden zur Manipulation von Fenstern und Senden von Tastatur- und Mausevents

        [DllImport("user32.dll")]
        // public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
        public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);

        [DllImport("user32.dll")]
        public static extern int SendMessage(
              int hWnd,     // handle to destination window
              uint Msg,     // message
              long wParam,  // first message parameter
              long lParam   // second message parameter
        );

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);

        [DllImport("USER32.DLL", EntryPoint = "PostMessageA", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        // used for button-down & button-up
        private static extern int PostMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        [DllImport("USER32.DLL", EntryPoint = "ShowWindow", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern int ShowWindow(IntPtr hWnd, int cmd);

        // Dies wird benötigt, um ein Fenster in den Vordergrund zu tun
        [DllImport("USER32.DLL", EntryPoint = "SetForegroundWindow", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetForegroundWindow(IntPtr hWnd);

        [DllImport("USER32.DLL", EntryPoint = "SetWindowPos", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        [DllImport("user32")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        // Dies wird benötigt um ein bitmap screen shot eines Fenster zu erhalten
        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(IntPtr hwnd, ref Rect rectangle);

        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowDC(IntPtr hwnd);

        [DllImport("user32.dll")]
        public static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);

        [DllImport("gdi32.dll")]
        public static extern bool BitBlt(IntPtr hdcDst, int xDst, int yDst, int cx, int cy, IntPtr hdcSrc, int xSrc, int ySrc, uint ulRop);

        #endregion


        #region Konstanten

        // Adressen der Maus- und Tastaturevents

        private const int MOUSEEVENTF_LEFTDOWN = 0x02;
        private const int MOUSEEVENTF_LEFTUP = 0x04;
        private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
        private const int MOUSEEVENTF_RIGHTUP = 0x10;

        private const int WM_LBUTTONDOWN = 0x0201;
        private const int WM_LBUTTONUP = 0x0202;
        private const int WM_RBUTTONDOWN = 0x0204;
        private const int WM_RBUTTONUP = 0x0205;

        private const int WM_KEYDOWN = 0x0100;
        private const int WM_KEYUP = 0x0101;

        #endregion


        #region Attribute

        private IntPtr MineSweeperHandle;

        // Attribut für die Grafik
        private Rect msRect = new Rect();

        /// <summary>
        /// Feld zur Berechnung der Lösung [y,x]
        /// 0: offenes Feld
        /// 1: Einer-Feld
        /// 2: Zweier-Feld
        /// 3: Dreier-Feld
        /// 4: Vierer-Feld
        /// 5: Fünfer-Feld
        /// 6: Sechser-Feld
        /// 7: Siebener-Feld
        /// 8: Achter-Feld        
        /// 9: verdecktes Feld        
        /// 10: markierte Bombe        
        /// 66: Explodierte Bombe
        /// </summary>
        private int[,] feld;

        // Liste mit Lösungen für erweiterte Suche
        List<int[,]> listeAdvLoesungen = new List<int[,]>();

        // Spiel zu ende?
        private bool spielVerloren;

        // Zeigt die Pixel an, die beim FeldEinlesen zur Erkennung benutzt werden
        private bool debug;

        // Durch Escape-Taste kann der Vorgang zum Lösen abgebrochen werden
        private bool abbruch;

        // Attribute für Statistiken
        private int foundedBombs;
        private int allFields;
        private int coveredFields;

        // public static extern IntPtr GetWindowDC(IntPtr hwnd);
        // public static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);
        // public static extern bool BitBlt(IntPtr hdcDst, int xDst, int yDst, int cx, int cy, IntPtr hdcSrc, int xSrc, int ySrc, uint ulRop);

        #endregion

        
        #region delegates

        // delegate für Berechnungen
        public delegate void solveDelegate();

        #endregion


        #region Konstruktoren

        /// <summary>
        /// Standard-Konstruktor
        /// </summary>
        public Hauptfenster()
        {
            InitializeComponent();
            foundedBombs = 0;
            allFields = 0;
            coveredFields = 0;
            spielVerloren = false;
        }

        #endregion


        #region Fensterbearbeitung

        /// <summary>
        /// Delegate for the EnumChildWindows method
        /// </summary>
        /// <param name="hWnd">Window handle</param>
        /// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
        /// <returns>True to continue enumerating, false to bail.</returns>
        public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

        /// <summary>
        /// Returns a list of child windows
        /// </summary>
        /// <param name="parent">Parent of the windows to return</param>
        /// <returns>List of child windows</returns>
        private static List<IntPtr> GetChildWindows(IntPtr parent)
        {
            List<IntPtr> result = new List<IntPtr>();
            GCHandle listHandle = GCHandle.Alloc(result);
            try
            {
                EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
                EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
            }
            finally
            {
                if (listHandle.IsAllocated)
                    listHandle.Free();
            }
            return result;
        }

        /// <summary>
        /// Callback method to be used when enumerating windows.
        /// </summary>
        /// <param name="handle">Handle of the next window</param>
        /// <param name="pointer">Pointer to a GCHandle that holds a reference to the list to fill</param>
        /// <returns>True to continue the enumeration, false to bail</returns>
        private static bool EnumWindow(IntPtr handle, IntPtr pointer)
        {
            GCHandle gch = GCHandle.FromIntPtr(pointer);
            List<IntPtr> list = gch.Target as List<IntPtr>;
            if (list == null)
            {
                throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
            }
            list.Add(handle);
            // You can modify this to check to see if you want to cancel the operation, then return a null here
            return true;
        }

        #endregion


        #region Mausaktionen

        /// <summary>
        /// Bewegt Maus auf Feld links oben in der Ecke
        /// </summary>
        private void startpos()
        {
            Cursor.Position = new Point(22-20, 63-20);
            System.Threading.Thread.Sleep(5);
        }


        /// <summary>
        /// Bewegt Maus an Feld(x, y)
        /// </summary>
        /// <param name="x">x-Koordinate des Minesweeperfelds</param>
        /// <param name="y">y-Koordinate des Minesweeperfelds</param>
        private void bewegeMaus(int x, int y)
        {
            Cursor.Position = new Point(47 + x * 18, 89 + y * 18);
            System.Threading.Thread.Sleep(5);
        }


        /// <summary>
        /// Bewegt Maus an Feld(x, y)
        /// </summary>
        /// <param name="x">x-Koordinate des Minesweeperfelds</param>
        /// <param name="y">y-Koordinate des Minesweeperfelds</param>
        private void bewegeMaus2(int x, int y)
        {
            Cursor.Position = new Point(47 + x * 18+1, 89 + y * 18+1);
            System.Threading.Thread.Sleep(5);
        }


        /// <summary>
        /// Führt einen Linksklick aus
        /// </summary>
        private void klickLinks()
        {
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
            System.Threading.Thread.Sleep(5);
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
            System.Threading.Thread.Sleep(10);
        }


        /// <summary>
        /// Führt einen Rechtsklick aus
        /// </summary>
        private void klickRechts()
        {
            mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
            System.Threading.Thread.Sleep(5);
            mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
            System.Threading.Thread.Sleep(10);
        }


        /// <summary>
        /// Führt einen Links- und Rechtsklick aus
        /// </summary>
        private void klickLinksRechts()
        {
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
            System.Threading.Thread.Sleep(5);
            mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
            System.Threading.Thread.Sleep(10);
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
            System.Threading.Thread.Sleep(5);
            mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
            System.Threading.Thread.Sleep(10);
        }


        /// <summary>
        /// Setzt ein Bombenzeichen auf ein übergebenes Feld
        /// </summary>
        /// <param name="x">x-Koordinate des Minesweeperfelds</param>
        /// <param name="y">y-Koordinate des Minesweeperfelds</param>
        private void setBomb(int x, int y)
        {
            feld[y, x] = 10;
            bewegeMaus(x, y);
            System.Threading.Thread.Sleep(20);
            klickRechts();
            System.Threading.Thread.Sleep(20);

            //startpos();

            //System.Threading.Thread.Sleep(50);
            //klickLinks();
            //System.Threading.Thread.Sleep(200);
            //bewegeMaus2(y, x );
            //System.Threading.Thread.Sleep(200);
        }


        /// <summary>
        /// Öffnet ein Feld an übergebener Position
        /// </summary>
        /// <param name="x">x-Koordinate des Minesweeperfelds</param>
        /// <param name="y">y-Koordinate des Minesweeperfelds</param>
        private void openField(int x, int y)
        {
            bewegeMaus(x, y);
            System.Threading.Thread.Sleep(20);
            klickLinks();
            System.Threading.Thread.Sleep(20);
        }


        /// <summary>
        /// Führt Chording an übergebener Position aus
        /// </summary>
        /// <param name="x">x-Koordinate des Minesweeperfelds</param>
        /// <param name="y">y-Koordinate des Minesweeperfelds</param>
        private void chording(int x, int y)
        {
            bewegeMaus(x, y);
            System.Threading.Thread.Sleep(20);
            klickLinksRechts();
            System.Threading.Thread.Sleep(20);
        }

        #endregion


        #region private Methoden

        /// <summary>
        /// Führt einen Einzelschritt aus zum Lösen des Spiels
        /// </summary>
        private void solveSingle()
        {
            Invoke(new System.Threading.ThreadStart(() => { disableSolveButtons(); }));

            bool allclosed;
            int maxx, maxy;

            if (feldEinlesen(out allclosed, out maxx, out maxy) == true)
            {
                if (allclosed == true)
                {
                    openField(0, 0);
                }
                else
                {
                    Invoke(new System.Threading.ThreadStart(() => { setStatus("Berechne Lösung. Benutze einfachen Algorithmus"); }));
                    if (easyTask(maxx, maxy) == false)
                    {
                        if (MessageBox.Show("Der einfache Algorithmus konnte keine Lösung finden.\nLösung mit erweitertem Algorithmus suchen?\nKönnte mehr Zeit in Anspruch nehmen.", "Erweiterten Algorithmus benutzen?", MessageBoxButtons.YesNo) == DialogResult.Yes)
                        {
                            Invoke(new System.Threading.ThreadStart(() => { setStatus("Berechne Lösung. Benutze erweiterten Algorithmus. Könnte mehrere Minuten dauern."); }));
                            if (advancedTask(maxx, maxy) == true)
                                Invoke(new System.Threading.ThreadStart(() => { setStatus("Bereit"); }));
                            else
                                Invoke(new System.Threading.ThreadStart(() => { setStatus("Erweiterter Algorithmus konnte keine Lösung finden."); }));
                        }
                        else
                            Invoke(new System.Threading.ThreadStart(() => { setStatus("Einfacher Algorithmus konnte keine Lösung finden."); }));
                    }
                    else
                        Invoke(new System.Threading.ThreadStart(() => { setStatus("Bereit"); }));
                }

                // Feld nach Lösen neu einlesen um Bild und Statistiken aktuell zu halten
                if (feldEinlesen(out allclosed, out maxx, out maxy) == false)
                    Invoke(new System.Threading.ThreadStart(() => { setStatus("Fehler beim Einlesen des Minesweeperfeldes."); }));
            }
            else
                Invoke(new System.Threading.ThreadStart(() => { setStatus("Fehler beim Einlesen des Minesweeperfeldes."); }));

            Invoke(new System.Threading.ThreadStart(() => { enableSolveButtons(); }));
            Application.DoEvents();
        }

        /// <summary>
        /// Löst das Spiel soweit es möglich ist
        /// </summary>
        private void solveAll()
        {
            Invoke(new System.Threading.ThreadStart(() => { disableSolveButtons(); }));

            bool erfolg = true;
            spielVerloren = false;
            bool allclosed;
            int maxx, maxy;
            int verdeckteFelderZuvor = -1;

            // Maximal 720 Durchläufe, da maxinmal 720 Felder existieren können.
            for (int ii = 0; ii < 720; ii++)
            {
                if (feldEinlesen(out allclosed, out maxx, out maxy) == true)
                {
                    if (spielVerloren == true)
                        Invoke(new System.Threading.ThreadStart(() => { setStatus("Eventuell Spiel verloren."); }));

                    // Spiel verloren, Alle Felder aufgedeckt, Algorithmus findet keine weitere Lösung. "spielVerloren == true || " auskommentiert im if
                    if (coveredFields == 0 || verdeckteFelderZuvor == coveredFields || !erfolg || abbruch)
                    {
                        Invoke(new System.Threading.ThreadStart(() => { setStatus("Bereit"); }));
                        Invoke(new System.Threading.ThreadStart(() => { enableSolveButtons(); }));
                        return;
                    }

                    verdeckteFelderZuvor = coveredFields;

                    if (allclosed == true)
                    {
                        openField(0, 0);
                    }
                    else
                    {
                        Invoke(new System.Threading.ThreadStart(() => { setStatus("Berechne Lösung. Benutze einfachen Algorithmus"); }));
                        if (easyTask(maxx, maxy) == false)
                        {
                            if (MessageBox.Show("Der einfache Algorithmus konnte keine Lösung finden.\nLösung mit erweitertem Algorithmus suchen?\nKönnte mehr Zeit in Anspruch nehmen.", "Erweiterten Algorithmus benutzen?", MessageBoxButtons.YesNo) == DialogResult.Yes)
                            {
                                Invoke(new System.Threading.ThreadStart(() => { setStatus("Berechne Lösung. Benutze erweiterten Algorithmus. Könnte mehrere Minuten dauern."); }));
                                if (advancedTask(maxx, maxy) == true)
                                    Invoke(new System.Threading.ThreadStart(() => { setStatus("Bereit"); }));
                                else
                                    erfolg = false;
                                Invoke(new System.Threading.ThreadStart(() => { setStatus("Erweiterter Algorithmus konnte keine Lösung finden."); }));
                            }
                            else
                            {
                                erfolg = false;
                                Invoke(new System.Threading.ThreadStart(() => { setStatus("Einfacher Algorithmus konnte keine Lösung finden."); }));
                            }
                        }
                        else
                            Invoke(new System.Threading.ThreadStart(() => { setStatus("Bereit"); }));
                    }

                    // Feld nach Lösen neu einlesen um Bild und Statistiken aktuell zu halten
                    //if (feldEinlesen(out allclosed, out maxx, out maxy) == false)
                    //    setStatus("Fehler beim Einlesen des Minesweeperfeldes.");

                    Application.DoEvents();
                }
                else
                {
                    Invoke(new System.Threading.ThreadStart(() => { setStatus("Fehler beim Einlesen des Minesweeperfeldes."); }));
                    Invoke(new System.Threading.ThreadStart(() => { enableSolveButtons(); }));
                    return;
                }                
            }
            Invoke(new System.Threading.ThreadStart(() => { enableSolveButtons(); }));
        }


        /// <summary>
        /// Beschafft sich den handle des Minesweeper Prozess. Positioniert und skaliert Minesweeper Fenster.
        /// Liest Minesweeper Feld aus und speichert Feld in Klassenattribut.
        /// Berechnet Statistiken
        /// </summary>
        /// <param name="allclosed">true, wenn alle Felder verdeckt sind</param>
        /// <param name="maxx">Breite des Felds in Kästchen</param>
        /// <param name="maxy">Höhe des Felds in Kästchen</param>
        /// <returns>true, wenn einlesen des Feldes erfolgreich war</returns>
        private bool feldEinlesen(out bool allclosed, out int maxx, out int maxy)
        {
            allclosed = false;
            maxx = 0;
            maxy = 0;

            // Holt MineSweeper-Prozess aus Prozessliste 
            Process[] ps = Process.GetProcessesByName("mineSweeper");
            if (ps.Length != 1)
                return false;
            Process p = ps[0];
            // Holt den Handle des Hauptfensters vom MineSweeper-Prozess
            MineSweeperHandle = p.MainWindowHandle;

            // Bringt Fenster in Vordergrund in originaler Größe
            SetForegroundWindow(MineSweeperHandle);
            ShowWindow(MineSweeperHandle, 1);
            SetWindowPos(MineSweeperHandle, IntPtr.Zero, 0, 0, 100, 100, 0x0040);

            GetWindowRect(MineSweeperHandle, ref msRect);
            allclosed = true;

            // Anzahl der Felder in x und y Richtung
            maxx = (msRect.Width - 76) / 18;
            maxy = (msRect.Height - 121) / 18;

            // Anzahl aller Felder
            allFields = maxx * maxy;

            // generiert Feld zur Berechnung der Lösung
            feld = new int[maxy, maxx];

            // create a bitmap from the visible clipping bounds of the graphics object from the window
            Bitmap bitmap = new Bitmap(maxx * 18, maxy * 18);

            // create a graphics object from the bitmap
            Graphics gfxBitmap = Graphics.FromImage(bitmap);

            // get a device context for the bitmap
            IntPtr hdcBitmap = gfxBitmap.GetHdc();

            // get a device context for the window
            IntPtr hdcWindow = GetWindowDC(MineSweeperHandle);
            int a = maxx * 18;
            int b = maxy * 18;
            // bitblt the window to the bitmap
            BitBlt(hdcBitmap, 0, 0, maxx * 18, maxy * 18, hdcWindow, 38, 80, 0x00CC0020);

            // release the bitmap's device context
            gfxBitmap.ReleaseHdc(hdcBitmap);

            ReleaseDC(MineSweeperHandle, hdcWindow);

            // dispose of the bitmap's graphics object
            gfxBitmap.Dispose();
            pbFeld.Image = bitmap;
            Application.DoEvents();
            //StreamWriter WStream = new StreamWriter("ausgabe.txt");
            int feldy;
            int feldx;

            // Pixel(11, 14) vom Kästchen
            int x = 11;
            int y = 14;
            int yv = 15;

            int R = 0;
            int G = 0;
            int B = 0;

            int Rv = 0;
            int Gv = 0;
            int Bv = 0;

            int Rf = 0;
            int Gf = 0;
            int Bf = 0;

            Color colorfeld;

            foundedBombs = 0;
            coveredFields = 0;

            for (feldy = 0; feldy < maxy; feldy++)
            {
                for (feldx = 0; feldx < maxx; feldx++)
                {
                    colorfeld = bitmap.GetPixel(x, y);
                    R = colorfeld.R;
                    G = colorfeld.G;
                    B = colorfeld.B;

                    colorfeld = bitmap.GetPixel(x, yv);
                    Rv = colorfeld.R;
                    Gv = colorfeld.G;
                    Bv = colorfeld.B;

                    colorfeld = bitmap.GetPixel((x + 2), y - 3);
                    Rf = colorfeld.R;
                    Gf = colorfeld.G;
                    Bf = colorfeld.B;

                    if (debug == true)
                    {
                        colorfeld = bitmap.GetPixel(x, y);
                        bitmap.SetPixel(x, y, Color.Black);
                        pbFeld.Image = bitmap;
                        Application.DoEvents();
                    }

                    //WStream.Write(Rf);
                    //WStream.Write(",");
                    //WStream.Write(Gf);
                    //WStream.Write(",");
                    //WStream.Write(Bf);
                    //WStream.Write("   ");
                    //WStream.Write(Environment.NewLine);

                    //bitmap.SetPixel(x + 2, y - 3, Color.Black);
                    //pbFeld.Image = bitmap;
                    //Application.DoEvents();

                    if (((Rf >= 0) && (Rf <= 20) && (Gf >= 0) && (Gf <= 20) && (Bf >= 110) && (Bf <= 130)))
                    {
                        feld[feldy, feldx] = 4;
                        allclosed = false;
                    }

                    else if ((R >= 60) && (R <= 65) && (G >= 75) && (G <= 85) && (B >= 185) && (B <= 192))
                    {
                        feld[feldy, feldx] = 1;
                        allclosed = false;
                    }

                    else if ((Rv >= 41) && (Rv <= 139) && (Gv >= 58) && (Gv <= 202) && (Bv >= 176) && (Bv <= 255))
                    {
                        feld[feldy, feldx] = 9;
                        ++coveredFields;
                    }

                    else if ((Rv >= 20) && (Rv <= 40) && (Gv >= 90) && (Gv <= 110) && (Bv >= 0) && (Bv <= 10))
                    {
                        feld[feldy, feldx] = 2;
                        allclosed = false;
                    }

                    else if ((R >= 0) && (R <= 135) && (G >= 0) && (G <= 50) && (B >= 0) && (B <= 50))
                    {
                        feld[feldy, feldx] = 5;
                        allclosed = false;
                    }

                    else if ((R >= 151) && (R <= 186) && (G >= 0) && (G <= 138) && (B >= 0) && (B <= 150))
                    {
                        y -= 3;
                        x -= 1;
                        colorfeld = bitmap.GetPixel(x, y);
  
                        // Application.DoEvents();
                        R = colorfeld.R;
                        G = colorfeld.G;
                        B = colorfeld.B;
                        y += 3;
                        x += 1;

                        if ((G >= 0) && (G <= 50) && (B >= 0) && (B <= 50))
                        {
                            feld[feldy, feldx] = 7;
                            allclosed = false;
                        }
                        else
                        {
                            y -= 3;
                            x -= 3;
                            colorfeld = bitmap.GetPixel(x, y);
                            R = colorfeld.R;
                            G = colorfeld.G;
                            B = colorfeld.B;
 
                            y += 3;
                            x += 3;

                            if ((G >= 0) && (G <= 50) && (B >= 0) && (B <= 50))
                            {
                                feld[feldy, feldx] = 8;
                                allclosed = false;
                            }
                            else
                            {
                                feld[feldy, feldx] = 3;
                                allclosed = false;
                            }
                        }
                    }
                    else if ((R >= 0) && (R <= 10) && (G >= 120) && (G <= 130) && (B >= 120) && (B <= 130))
                    {
                        feld[feldy, feldx] = 6;
                        allclosed = false;
                    }
                    else if ((Rv >= 153) && (Rv <= 163) && (Gv >= 152) && (Gv <= 161) && (Bv >= 158) && (Bv <= 164))
                    {
                        feld[feldy, feldx] = 10;
                        allclosed = false;
                        ++foundedBombs;
                    }
                    else
                    {
                        y -= 3;
                        x -= 1;
                        colorfeld = bitmap.GetPixel(x, y);

                        R = colorfeld.R;
                        G = colorfeld.G;
                        B = colorfeld.B;
                        y += 3;
                        x += 1;

                        if ((G >= 0) && (G <= 50) && (B >= 0) && (B <= 50))
                        {
                            feld[feldy, feldx] = 7;
                            allclosed = false;
                        }
                        else
                        {
                            y -= 4;
                            x -= 2;
                            colorfeld = bitmap.GetPixel(x, y);

                            R = colorfeld.R;
                            G = colorfeld.G;
                            B = colorfeld.B;
     
                            y += 4;
                            x += 2;

                            if ((R < 130) || ((R >= 151) && (R <= 186) && (G >= 0) && (G <= 138) && (B >= 0) && (B <= 150)))
                            {
                                // FEHLER
                                spielVerloren = true;
                                feld[feldy, feldx] = 66;
                            }
                            else
                            {
                                feld[feldy, feldx] = 0;
                                allclosed = false;
                            }
                        }
                    }
                    x += 18;
                }
                if (feldy == 3)
                    y++;
                yv += 18;
                y += 18;
                x = 11;

                // debughilfen:
                //StreamWriter WStream = new StreamWriter("ausgabe.txt");
                //WStream.Write(R);
                //WStream.Write(",");
                //WStream.Write(G);
                //WStream.Write(",");
                //WStream.Write(B);
                //WStream.Write("   ");
                //WStream.Write(Environment.NewLine);
                //WStream.Close();
                //colorfeld = bitmap.GetPixel(x, y);
                //bitmap.SetPixel(x, y, Color.Black);
                //pictureBox1.Image = bitmap;
                //Application.DoEvents();
            }
            //WStream.Close();
            loadStatistics();
            return true;
        }


        /// <summary>
        /// Die Funktion easyTask führt einfache und effizente Funktionen aus, um das Minsweeperspiel zu lösen
        /// </summary>
        /// <param name="maxx">Breite des Felds in Kästchen</param>
        /// <param name="maxy">Höhe des Felds in Kästchen</param>
        /// <returns>true, wenn erfolgreich mindestens eine Mine entdeckt wurde und/oder mindestens ein Feld aufgedeckt wurde</returns>
        private bool easyTask(int maxx, int maxy)
        {
            int anzahlVerdeckt;
            int anzahlBomben;

            // es werd das ganze Array, mit allen Feldern durchgegangen
            for (int y = 0; y < maxy; y++)
            {
                for (int x = 0; x < maxx; x++)
                {
                    // Wenn sich im aktuellen Feld eine 0 (offenes Feld), eine 9 (geschlossenes Feld) oder eine 10 (markierte Bombe)
                    // befindet wird das nächste Feld begutachtet
                    if (isopen(x, y, maxx, maxy) == true && feld[y, x] != 10 && feld[y, x] != 0)
                    {
                        anzahlVerdeckt = countSurround(x, y, maxx, maxy, 9);
                        anzahlBomben = countSurround(x, y, maxx, maxy, 10);

                        // Wenn genau so viele verdeckte Felder, wie das Feld anzeigt, das es Bomben gibt, wird eine Funktion aufgerufen, die die umliegenden verdeckten Felder als 
                        // Bomben markiert
                        if ((feld[y, x] == anzahlVerdeckt + anzahlBomben) && anzahlVerdeckt != 0)
                        {
                           easyBombMark(x, y, maxx, maxy);
                            // gut = true;
                        }

                        // Wenn die Zahl des Feldes und die markierten Bomben übereinstimmt, wird eine Fuktion aufgerufen, die alle umliegenden geschlossenen Felder öffnet
                        else if ((feld[y, x] == anzahlBomben) && anzahlVerdeckt != 0)
                        {
                            chording(x, y);
                            return true;
                            // gut = true;
                        }

                        else if (pattern121(x, y, maxx, maxy) == true)
                        {
                            return true;
                            // gut = true;
                        }
                        else if (pattern1221(x, y, maxx, maxy) == true)
                        {
                            return true;
                            // gut = true;
                        }
                    }
                }
            }
            return false;
        }


        /// <summary>
        /// Die Funktion countSorround zählt wie oft in benachbarten Feldern eines Feld die Zahl, die mit dem Parameter search übergeben wird.
        /// Es wird beachtet ob das Feld am Rand des Arrays liegt
        /// </summary>
        /// <param name="field">Übergebenes Feld, das überprüft wird</param>
        /// <param name="x">x-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="y">y-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="maxx">Breite des Felds in Kästchen</param>
        /// <param name="maxy">Höhe des Felds in Kästchen</param>
        /// <param name="search">Zahl nach der in den anliegenden Feldern gesucht wird</param>
        /// <returns>Anzahl, wie oft die gesuchte Zahl in den anliegenden Kästen vorkommt</returns>
        private int countSurround(int[,] field, int x, int y, int maxx, int maxy, int search)
        {
            int hitcount = 0;
            if (((x - 1) >= 0) && ((y - 1) >= 0))
            {
                if (field[y - 1, x - 1] == search)
                {
                    hitcount++;
                }
            }
            if ((x + 1) < maxx && ((y + 1) < maxy))
            {
                if (field[y + 1, x + 1] == search)
                {
                    hitcount++;
                }
            }
            if (((x - 1) >= 0) && ((y + 1) < maxy))
            {
                if (field[y + 1, x - 1] == search)
                {
                    hitcount++;
                }
            }
            if (((x + 1) < maxx) && ((y - 1) >= 0))
            {
                if (field[y - 1, x + 1] == search)
                {
                    hitcount++;
                }
            }
            if ((y - 1) >= 0)
            {
                if (field[y - 1, x] == search)
                {
                    hitcount++;
                }
            }
            if ((y + 1) < maxy)
            {
                if (field[y + 1, x] == search)
                {
                    hitcount++;
                }
            }
            if ((x - 1) >= 0)
            {
                if (field[y, x - 1] == search)
                {
                    hitcount++;
                }
            }
            if ((x + 1) < maxx)
            {
                if (field[y, x + 1] == search)
                {
                    hitcount++;
                }
            }
            return hitcount;
        }


        /// <summary>
        /// Die Funktion countSorround zählt wie oft in benachbarten Feldern eines Feld die Zahl, die mit dem Parameter search übergeben wird.
        /// Es wird beachtet ob das Feld am Rand des Arrays liegt
        /// </summary>
        /// <param name="x">x-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="y">y-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="maxx">Breite des Felds in Kästchen</param>
        /// <param name="maxy">Höhe des Felds in Kästchen</param>
        /// <param name="search">Zahl nach der in den anliegenden Feldern gesucht wird</param>
        /// <returns>Anzahl, wie oft die gesuchte Zahl in den anliegenden Kästen vorkommt</returns>
        private int countSurround(int x, int y, int maxx, int maxy, int search)
        {
            int hitcount = 0;

            if (((x - 1) >= 0) && ((y - 1) >= 0))
            {
                if (feld[y - 1, x - 1] == search)
                {
                    hitcount++;
                }
            }
            if (((x + 1) < maxx) && ((y + 1) < maxy))
            {
                if (feld[y + 1, x + 1] == search)
                {
                    hitcount++;
                }
            }
            if (((x - 1) >= 0) && ((y + 1) < maxy))
            {
                if (feld[y + 1, x - 1] == search)
                {
                    hitcount++;
                }
            }
            if (((x + 1) < maxx) && ((y - 1) >= 0))
            {
                if (feld[y - 1, x + 1] == search)
                {
                    hitcount++;
                }
            }
            if ((y - 1) >= 0)
            {
                if (feld[y - 1, x] == search)
                {
                    hitcount++;
                }
            }
            if ((y + 1) < maxy)
            {
                if (feld[y + 1, x] == search)
                {
                    hitcount++;
                }
            }
            if ((x - 1) >= 0)
            {
                if (feld[y, x - 1] == search)
                {
                    hitcount++;
                }
            }
            if ((x + 1) < maxx)
            {
                if (feld[y, x + 1] == search)
                {
                    hitcount++;
                }
            }
            return hitcount;
        }


        /// <summary>
        /// Die Funktion isopen zählt wie oft in benachbarten Feldern ein offenes Feld eingelesen wurde, also ein Zahlen-Feld oder offenes Feld
        /// </summary>
        /// <param name="x">x-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="y">y-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="maxx">Breite des Felds in Kästchen</param>
        /// <param name="maxy">Höhe des Felds in Kästchen</param>
        /// <returns>Anzahl wieviele benachbarte Kästchen offen sind</returns>
        private bool isopen(int x, int y, int maxx, int maxy)
        {
            int[] open = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };

            if (((x - 1) >= 0) && ((y - 1) >= 0))
            {
                if (open.Contains(feld[y - 1, x - 1]) == true)
                {
                    return true;
                }
            }
            if (((x + 1) < maxx) && ((y + 1) < maxy))
            {
                if (open.Contains(feld[y + 1, x + 1]) == true)
                {
                    return true;
                }
            }
            if (((x - 1) >= 0) && ((y + 1) < maxy))
            {
                if (open.Contains(feld[y + 1, x - 1]) == true)
                {
                    return true;
                }
            }
            if (((x + 1) < maxx) && ((y - 1) >= 0))
            {
                if (open.Contains(feld[y - 1, x + 1]) == true)
                {
                    return true;
                }
            }
            if ((y - 1) >= 0)
            {
                if (open.Contains(feld[y - 1, x]) == true)
                {
                    return true;
                }
            }
            if ((y + 1) < maxy)
            {
                if (open.Contains(feld[y + 1, x]) == true)
                {
                    return true;
                }
            }
            if ((x - 1) >= 0)
            {
                if (open.Contains(feld[y, x - 1]) == true)
                {
                    return true;
                }
            }
            if ((x + 1) < maxx)
            {
                if (open.Contains(feld[y, x + 1]) == true)
                {
                    return true;
                }
            }
            return false;
        }


        /// <summary>
        /// Die Funktion easyBombMark wandelt alle umliegenden, geschlossenen Felder in Bomben um
        /// </summary>
        /// <param name="xb">x-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="yb">y-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="maxx">Höhe des Felds in Kästchen</param>
        /// <param name="maxy">Breite des Felds in Kästchen</param>
        public void easyBombMark(int xb, int yb, int maxx, int maxy)
        {
            if ((yb - 1) >= 0)
            {
                if (feld[yb - 1, xb] == 9)
                {
                    setBomb((xb), (yb - 1));
                }
            }
            if (((xb + 1) < maxx) && ((yb - 1) >= 0))
            {
                if (feld[yb - 1, xb + 1] == 9)
                {
                    setBomb((xb + 1), (yb - 1));
                }
            }
            if ((xb + 1) < maxx)
            {
                if (feld[yb, xb + 1] == 9)
                {
                    setBomb((xb + 1), (yb));
                }
            }
            if (((xb + 1) < maxx) && ((yb + 1) < maxy))
            {
                if (feld[yb + 1, xb + 1] == 9)
                {
                    setBomb((xb + 1), (yb + 1));
                }
            }
            if ((yb + 1) < maxy)
            {
                if (feld[yb + 1, xb] == 9)
                {
                    setBomb((xb), (yb + 1));
                }
            }
            if (((xb - 1) >= 0) && ((yb + 1) < maxy))
            {
                if (feld[yb + 1, xb - 1] == 9)
                {
                    setBomb((xb - 1), (yb + 1));
                }
            }
            if ((xb - 1) >= 0)
            {
                if (feld[yb, xb - 1] == 9)
                {
                    setBomb((xb - 1), (yb));
                }
            }
            if (((xb - 1) >= 0) && ((yb - 1) >= 0))
            {
                if (feld[yb - 1, xb - 1] == 9)
                {
                    setBomb((xb - 1), (yb - 1));
                }
            }
        }


        /// <summary>
        /// Die Funktion pattern1 überprüft ob das aktuelle Feld zum Pattern 121 gehört.
        /// Wenn dem so ist, werden die Bomben gemäß des Patterns verteilt(bombe, offen, bombe)
        /// </summary>
        /// <param name="x">x-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="y">y-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="maxx">Breite des Felds in Kästchen</param>
        /// <param name="maxy">Höhe des Felds in Kästchen</param>
        /// <returns>true, wenn patternmatching erfolg hat</returns>
        public bool pattern121(int x, int y, int maxx, int maxy)
        {
            if ((((x + 2) < maxx) && ((feld[y, x] - countSurround(x, y, maxx, maxy, 10) == 1) && (feld[y, x + 1] - countSurround(x + 1, y, maxx, maxy, 10)) == 2 && (feld[y, x + 2] - countSurround(x + 2, y, maxx, maxy, 10) == 1))))
            {
                if ((y + 1) < maxy && (feld[y + 1, x] == 9 && feld[y + 1, x + 1] == 9 && feld[y + 1, x + 2] == 9))
                {
                    setBomb((x), (y + 1));
                    setBomb((x + 2), (y + 1));
                    //chording((x + 1), (y));                

                    return true;
                }
                else if ((y - 1) > 0 && (feld[y - 1, x] == 9 && feld[y - 1, x + 1] == 9 && feld[y - 1, x + 2] == 9))
                {
                    setBomb((x), (y - 1));
                    setBomb((x + 2), (y - 1));
                    //chording((x + 1), (y - 1));

                    return true;
                }
            }
            else if (((y + 3) < maxy) && (feld[y, x] == 1 - countSurround(x, y, maxx, maxy, 10) && feld[y + 1, x] - countSurround(x, y + 1, maxx, maxy, 10) == 2 && feld[y + 2, x] - countSurround(x, y + 2, maxx, maxy, 10) == 1))
            {
                if ((x + 1) < maxx && (feld[y, x + 1] == 9 && feld[y + 1, x + 1] == 9 && feld[y + 2, x + 1] == 9))
                {
                    setBomb((x + 1), (y));
                    setBomb((x + 1), (y + 2));
                    //chording((x + 1), (y + 1));
                      return true;
                }
                else if ((y - 1) > 0 && (feld[y - 1, x] == 9 && feld[y - 1, x + 1] == 9 && feld[y - 1, x + 2] == 9))
                {
                    setBomb((x - 1), (y));
                    setBomb((x - 1), (y + 2));
                    //chording((x - 1), (y + 1));

                    return true;
                }
            }
            return false;
        }


        /// <summary>
        /// Die Funktion patter2 überprüft ob das aktuelle Feld zum Pattern 1221 gehört.
        /// Wenn dem so ist, werden die Bomben gemäß des Patterns verteilt (offen, Bombe, Bombe, offen)
        /// </summary>
        /// <param name="x">x-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="y">y-Koordinate des Felds, mit dem gearbeitet wird</param>
        /// <param name="maxx">Breite des Felds in Kästchen</param>
        /// <param name="maxy">Höhe des Felds in Kästchen</param>
        /// <returns>true, wenn patternmatching erfolg hat</returns>
        public bool pattern1221(int x, int y, int maxx, int maxy)
        {
            if ((((x + 3) < maxx) && (feld[y, x] == 1 - countSurround(x, y, maxx, maxy, 10) && feld[y, x + 1] - countSurround(x + 1, y, maxx, maxy, 10) == 2 && feld[y, x + 2] - countSurround(x + 2, y, maxx, maxy, 10) == 2 && feld[y, x + 3] - countSurround(x + 3, y, maxx, maxy, 10) == 1)))
            {
                if ((y + 1) < maxy && (feld[y + 1, x] == 9 && feld[y + 1, x + 1] == 9 && feld[y + 1, x + 2] == 9 && feld[y + 1, x + 3] == 9))
                {
                    setBomb((x + 1), (y + 1));
                    setBomb((x + 2), (y + 1));
                    chording((x), (y + 1));
                    chording((x + 3), (y + 1));
                    return true;
                }
                else if ((y - 1) > 0 && (feld[y - 1, x] == 9 && feld[y - 1, x + 1] == 9 && feld[y - 1, x + 2] == 9 && feld[y - 1, x + 3] == 9))
                {
                    setBomb((x + 1), (y - 1));
                    setBomb((x + 2), (y - 1));
                    chording((x), (y - 1));
                    chording((x + 3), (y - 1));
                    return true;
                }
            }
            else if (((y + 3) < maxy) && (feld[y, x] - countSurround(x, y, maxx, maxy, 10) == 1 && feld[y + 1, x] - countSurround(x, y + 1, maxx, maxy, 10) == 2 && feld[y + 2, x] - countSurround(x, y + 2, maxx, maxy, 10) == 2 && feld[y + 3, x] - countSurround(x, y + 3, maxx, maxy, 10) == 1))
            {
                if ((x + 1) < maxx && (feld[y, x + 1] == 9 && feld[y + 1, x + 1] == 9 && feld[y + 2, x + 1] == 9 && feld[y + 3, x + 1] == 9))
                {
                    setBomb((x +1), (y + 1));
                    setBomb((x + 1), (y + 2));
                    chording((x + 1), (y));
                    chording((x + 1), (y + 3));
                    return true;
                }
                else if ((x - 1) > 0 && (feld[y, x - 1] == 9 && feld[y + 1, x - 1] == 9 && feld[y + 2, x - 2] == 9 && feld[y + 3, x - 3] == 9))
                {
                    setBomb((x - 1), (y + 1));
                    setBomb((x - 1), (y + 2));
                    chording((x - 1), (y));
                    chording((x - 1), (y + 3));
                    return true;
                }
            }
            return false;
        }


        /// <summary>
        /// Alle offenen Felder, die an ein geschlossenes Feld grenzen, werden in der Liste listeOffeneFelder gesammelt.
        /// Alle geschlossenen Felder, die an ein offenes Feld grenzen, werden in der Liste listeverdeckteFelder gesammelt.
        /// Über eine Rekursion werden alle Möglichkeiten, wie die Bomben verteilt sind auf Gültigkeit verifiziert
        /// und in die Liste listeAdvLoesungen gesetzt.
        /// Enthält die Liste listeAdvLoesungen nur eine Lösung wird das Spiel anhand dieser Lösung beendet.
        /// Enthält die Liste listeAdvLoesungen mehrere Lösungen, wird überprüft ob auf einer Position in allen Lösungen
        /// ein gleicher Wert gespeichert ist. Falls es solche Feldkästchen gibt, werden diese geöffnet bzw. eine Bombe wird gesetzt.
        /// Gibt es nur unterschiedliche Lösungen, gibt die Methode false zurück.
        /// </summary>
        /// <param name="maxx">Breite des Felds in Kästchen</param>
        /// <param name="maxy">Höhe des Felds in Kästchen</param>
        /// <returns>true, wenn mindestens eine weitere Lösung gefunden wurde</returns>
        private bool advancedTask(int maxx, int maxy)
        {
            bool erfolg = false;

            listeAdvLoesungen.Clear();

            List<advOffeneFelder> listeOffeneFelder = new List<advOffeneFelder>();
            List<advVerdeckteFelder> listeverdeckteFelder = new List<advVerdeckteFelder>();
            
            // int[y, x]
            int[,] feld2 = (int[,]) feld.Clone();

            int x, y;

            advOffeneFelder offenesFeld = new advOffeneFelder();
            advVerdeckteFelder verdecktesFeld = new advVerdeckteFelder();

            // Zähle verdeckte Felder, die an offene Grenzen und offene Felder, die an verdeckte Grenzen
            for (y = 0; y < maxy; y++)
            {
                for (x = 0; x < maxx; x++)
                {
                    // wenn ein Feld offen ist und mind ein verdecktes Feld angrenzt wird das Feld zur Liste listeOffeneFelder hinzugefügt
                    if (feld[y, x] != 9 && feld[y, x] != 10 && countSurround(x, y, maxx, maxy, 9) != 0)
                    {
                        offenesFeld.x = x;
                        offenesFeld.y = y;
                        listeOffeneFelder.Add(offenesFeld);
                    }

                    // wenn ein Feld geschlossen ist und mind ein offenes Feld angrenzt wird das Feld zur Liste listeverdeckteFelder hinzugefügt
                    if ((feld[y, x] == 9) && (isopen(x, y, maxx, maxy) == true))
                    {
                        verdecktesFeld.x = x;
                        verdecktesFeld.y = y;
                        listeverdeckteFelder.Add(verdecktesFeld);
                    }
                }
            }

            // Fügt alle Kombinationen der Liste listeAdvLoesungen hinzu
            if (advancedRek(0, listeOffeneFelder, listeverdeckteFelder, feld2, maxx, maxy) == false)
                return false;

            switch (listeAdvLoesungen.Count)
            {
                // keine Lösung gefunden
                case 0:
                    Invoke(new System.Threading.ThreadStart(() => { setStatus("Keine Lösung gefunden"); }));
                    return false;

                // genau eine Lösung für Feldmuster gefunden --> richtige Lösung
                case 1:
                    feld2 = (int[,]) listeAdvLoesungen[0].Clone();
                    for (y = 0; y < maxy; y++)
                    {
                        for (x = 0; x < maxx; x++)
                        {
                            // 11 bedeutet, dass unterm Feld keine Bombe ist und es sich um ein verdecktes Feld handelt
                            if (feld2[y, x] == 11)
                            {
                                openField(x, y);
                            }
                        }
                    }
                    return true;

                // mehrere Lösungen für Feldmuster gefunden. Überprüfe ob einzelne Kästchen bei allen Lösungen ein gleicher Zustand existiert
                default:    
                    // Feld das die Anzahl gleicher Kästchen der verschiedenen Lösungen speichert
                    int[,] feldHaeufigkeit = new int[maxy, maxx];
                            
                    // Initialisiert feldHaeufigkeit überall mit 0
                    for (y = 0; y < maxy; y++)
                    {
                        for (x = 0; x < maxx; x++)
                        {
                            feldHaeufigkeit[y, x] = 0;
                        }
                    }
                    
                    foreach (int[,] feld3 in listeAdvLoesungen)
                    {
                        for (y = 0; y < maxy; y++)
                        {
                            for (x = 0; x < maxx; x++)
                            {
                                // 11 bedeutet, dass unterm Feld keine Bombe ist und es sich um ein verdecktes Feld handelt
                                if (feld3[y, x] == 11)
                                {
                                    feldHaeufigkeit[y, x]++;
                                }
                                else
                                    // 12 bedeutet, dass unter dem Feld eine Bombe ist
                                    if (feld3[y, x] == 12)
                                        feldHaeufigkeit[y, x]--;
                            }
                        }
                    }

                    // Überprüft Feld, ob ein Kästchen in allen Lösungen gleich ist
                    for (y = 0; y < maxy; y++)
                    {
                        for (x = 0; x < maxx; x++)
                        {
                            // In allen Lösungen befindet sich keine Bombe unter diesem Feld. Anzahl Lösungen == Zustände Kästchen
                            // keine Bombe positiv
                            if (feldHaeufigkeit[y, x] == listeAdvLoesungen.Count)
                            {
                                openField(x, y);
                                erfolg = true;
                            }
                            else
                                // In allen Lösungen befindet sich eine Bombe unter diesem Feld. Anzahl Lösungen * -1 == Zustände Kästchen
                                // Bombe negativ
                                if (feldHaeufigkeit[y, x] == -1 * listeAdvLoesungen.Count)
                                {
                                    setBomb(x, y);
                                    erfolg = true;
                                }
                        }
                    }
                    return erfolg;
            }
        }

        /// <summary>
        /// Erstellt alle möglichen Kombinationen, ob die verdeckten Felder eine Bombe oder keine Bombe haben.
        /// </summary>
        /// <param name="rekTiefe">aktuelle Rekursionstiefe, maximal: Anzahl verdeckter Felder</param>
        /// <param name="listOpenFields">Liste mit den offenen Feldern</param>
        /// <param name="listCoveredFields">Liste mit den verdeckten Feldern</param>
        /// <param name="feld2">Lösungsfeld</param>
        /// <param name="maxx">Breite des Felds in Kästchen</param>
        /// <param name="maxy">Höhe des Felds in Kästchen</param>
        private bool advancedRek(int rekTiefe, List<advOffeneFelder> listOpenFields, List<advVerdeckteFelder> listCoveredFields, int[,] feld2, int maxx, int maxy)
        {
            // Überprüfe ob Lösung gültig ist
            foreach (advOffeneFelder advOF in listOpenFields)
            {
                // Abbruch, wenn zu viele Bomben für eine Kombination gesetzt wurden
                if ( (countSurround(feld2, advOF.x, advOF.y, maxx, maxy, 10) + countSurround(feld2, advOF.x, advOF.y, maxx, maxy, 12)) > feld2[advOF.y, advOF.x])
                {
                    return true;
                }
            }

            // Abbruch durch Benuter
            if (abbruch == true)
                return false;

            // wenn alle Elemente von Liste listeverdeckteFelder durchlaufen wurden, kann Kombination der Liste hinzugefügt werden.
            if (listCoveredFields.Count() == rekTiefe)
            {
                // Überprüfe ob Lösung gültig ist
                foreach (advOffeneFelder advOF in listOpenFields)
                {
                    // Abbruch, wenn zu viele oder zu wenig Bomben für eine Kombination gesetzt wurden
                    if ((countSurround(feld2, advOF.x, advOF.y, maxx, maxy, 10) + countSurround(feld2, advOF.x, advOF.y, maxx, maxy, 12)) != feld2[advOF.y, advOF.x])
                    {
                        return true;
                    }
                }

                listeAdvLoesungen.Add( (int[,]) feld2.Clone() );
                return true;
            }

            // Rekursion mit Bombe. 12 steht für Bombe
            feld2[listCoveredFields.ElementAt(rekTiefe).y, listCoveredFields.ElementAt(rekTiefe).x] = 12;
            advancedRek(rekTiefe + 1, listOpenFields, listCoveredFields, feld2, maxx, maxy);

            // Rekursion mit keiner Bombe. 11 steht für keine Bombe
            feld2[listCoveredFields.ElementAt(rekTiefe).y, listCoveredFields.ElementAt(rekTiefe).x] = 11;
            advancedRek(rekTiefe + 1, listOpenFields, listCoveredFields, feld2, maxx, maxy);

            return true;
        }


        /// <summary>
        /// Läd die Statistiken des Spiels
        /// </summary>
        private void loadStatistics()
        {
            //lblAllBombs.Text = ;
            lblFoundedBombs.Text = foundedBombs.ToString();
            lblAllFields.Text = allFields.ToString();
            lblCoveredFields.Text = coveredFields.ToString();
        }


        /// <summary>
        /// Setzt den Text der Statuszeile
        /// </summary>
        /// <param name="statusText">Text für Statuszeile</param>
        private void setStatus(string statusText)
        {
            toolStripStatusLabel1.Text = statusText;
            Application.DoEvents();
        }


        /// <summary>
        /// Aktiviert Schaltflächen zum Lösen
        /// </summary>
        private void enableSolveButtons()
        {
            btnSingle.Enabled = true;
            btnSolve.Enabled = true;
        }


        /// <summary>
        /// Deaktiviert Schaltflächen zum Lösen
        /// </summary>
        private void disableSolveButtons()
        {
            btnSingle.Enabled = false;
            btnSolve.Enabled = false;
        }
      
        #endregion


        #region Events

        // Menüleiste --> Datei --> Beenden
        private void beendenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }


        // Menüleiste --> Hilfe --> Info
        private void infoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Öffnet neues Formular mit Infos zum Programm
            Info info = new Info();
            info.ShowDialog();
        }


        // Einzelschritt zum Lösen des Minesweeperspiels
        private void btnSingle_Click(object sender, EventArgs e)
        {
            abbruch = false;
            
            // Delegate für ThreadStart
            solveDelegate del = new solveDelegate(solveSingle);

            ThreadStart start = new ThreadStart(del);

            // Starte Berechnung in neuem Thread
            Thread solveThread = new Thread(start);
            solveThread.Start();

            //solveSingle();
        }


        // Löst das Minesweeperspiel soweit möglich
        private void btnSolve_Click(object sender, EventArgs e)
        {
            abbruch = false;

            // Delegate für ThreadStart
            solveDelegate del = new solveDelegate(solveAll);

            ThreadStart start = new ThreadStart(del);

            // Starte Berechnung in neuem Thread
            Thread solveThread = new Thread(start);
            solveThread.Start();

            //solveAll();
        }


        // Startet den Microsoft Windows Minesweeper
        private void btnStartMS_Click(object sender, EventArgs e)
        {
            // Überprüft ob Betriebssystem ein Windows NT Betriebssystem ist
            if (System.Environment.OSVersion.Platform == PlatformID.Win32NT)
            {
                // Überprüft ob es sich um Windows 7/Windows Server 2008 handelt
                Version verWin7 = new Version(6, 1);
                if (System.Environment.OSVersion.Version.Major == verWin7.Major && System.Environment.OSVersion.Version.Minor == verWin7.Minor)
                {
                    Process minesweeper = new Process();

                    minesweeper.StartInfo.FileName = "mineSweeper.exe";

                    // Pfad von Minesweeper unterscheidet sich bei 32 Bit und 64 Bit Betriebssystem
                    if (System.Environment.Is64BitOperatingSystem == true)
                        minesweeper.StartInfo.WorkingDirectory = @"C:\Windows\winsxs\amd64_microsoft-windows-s..oxgames-minesweeper_31bf3856ad364e35_6.1.7600.16385_none_fe560f0352e04f48";
                    else
                        minesweeper.StartInfo.WorkingDirectory = @"C:\Windows\winsxs\x86_microsoft-windows-s..oxgames-minesweeper_31bf3856ad364e35_6.1.7600.16385_none_a237737f9a82de12";

                    // Startet Windows Minesweeper Prozess
                    try
                    {
                        minesweeper.Start();
                    }
                    catch (Win32Exception ex)
                    {
                        setStatus(ex.ToString());
                    }
                }
                else
                    setStatus("Sie verwenden nicht Windows 7.");
            }
            else
                setStatus("Betriebssystem konnte nicht ermittelt werden.");
        }

        // Abbruch des Lösenvorgangs durch Escape
        private void Hauptfenster_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
                abbruch = true;
        }

        // Debugmodus an- bzw. ausschalten
        private void cbDebug_CheckedChanged(object sender, EventArgs e)
        {
            if (cbDebug.CheckState == CheckState.Checked)
                debug = true;
            else
                debug = false;
        }

        // Klick Event um Feld einzulesen
        private void btnFeldEinlesen_Click(object sender, EventArgs e)
        {
            bool allclosed;
            int maxx, maxy;

            if (feldEinlesen(out allclosed, out maxx, out maxy) == false)
                setStatus("Fehler beim Einlesen des Minesweeperfeldes.");

            Application.DoEvents();
        }

        // Starte Programm neu
        private void btnRestartApp_Click(object sender, EventArgs e)
        {
            Application.Restart();
        }

        #endregion
    }
}